#include "ext2.h"

// Prints a string
void prints(char* str)
{
	while ((*str) != '\0')
	{
		putc(*(str++));
	}
}

// Gets a string
void gets(char* input)
{
	do
	{
		*input = getc();
		putc(*input);
	} while (*(input++) != '\r');
	*(input - 1) = '\0';
}

// Gets the disk block and stores it in buf
void getblk(unsigned int blk, char* buf)
{
	blk *= 2;
	diskr(blk / 36, (blk / 18) % 2, blk % 18, buf);
}

// Finds an Ext2DirEnt with the specified name
Ext2DirEnt* findDirEnt(char* blk, char* name)
{
	int i = 0, j = 0;
	char tmpName[256];
	for (i = 0; i < 1024; i += ((Ext2DirEnt*)(blk))->rec_len)
	{
		for (j = 0; j < ((Ext2DirEnt*)(blk))->name_len; ++j)
		{
			tmpName[j] = ((Ext2DirEnt*)(blk))->name[j];
		}
		tmpName[j] = '\0';
		if (strcmp(name, tmpName) == 0)
			return blk;
		blk += ((Ext2DirEnt*)(blk))->rec_len;
	}
	return 0;
}

int main()
{
	int i = 0, size = 0;
	char buf[1024], kernel[256];
	Ext2DirEnt* dirent = 0;
	Ext2Inode* kernelInode = 0;
	
	// Prompt for a kernel name
	prints("boot: ");
	gets(kernel);
	
	// If no name is given use "mtx"
	if (kernel[0] == 0)
	{
		kernel[0] = 'm';
		kernel[1] = 't';
		kernel[2] = 'x';
		kernel[3] = '\0';
	}
	
	// Read in the root inode
	getblk(5, buf);
		
	// Read the root inodes first data block
	i = ((Ext2Inode*)(buf + 128))->i_block[0];
	getblk(i, buf);
		
	// Find the /boot directory
	dirent = findDirEnt(buf, "boot");
	
	// Read the block that has the /boot inode
	i = dirent->inode;
	getblk((i / 8) + 5, buf);
		
	// Read /boot's first data block
	i = ((Ext2Inode*)(buf + (128 * ((i - 1) % 8))))->i_block[0];
	getblk(i, buf);
	
	// Find the kernel
	dirent = findDirEnt(buf, kernel); 
	
	// Get the inode block with the mxt inode
	i = dirent->inode;
	getblk((i / 8) + 5, buf);
			
	// Get the mtx inode
	kernelInode = ((Ext2Inode*)(buf + (128 * ((i - 1) % 8))));
	size = kernelInode->i_blocks;
			
	// Load the direct blocks into memory
	setes(0x1000);
	for (i = 0; ((i < 12) && (size > 0)); ++i)
	{
		getblk(kernelInode->i_block[i], 0);
		inces();
		size -= 2;
	}
		
	// Load the indirect blocks into memory
	if (size > 0)
	{		
		// Load the first indirect block
		setes(0x9000);
		i = kernelInode->i_block[12];
		getblk(i, buf);
			
		// Start loading the blocks
		setes(0x1300);
		for (i = 0; size > 0; i += 4)
		{
			getblk(buf[i], 0);
			inces();
			size -= 2;
		}
	}
	
	return 1;
}
